package com.lanan.springboot.controller.api;

import com.lanan.springboot.exception.ApiAssert;
import com.lanan.springboot.exception.ApiException;
import com.lanan.springboot.model.Code;
import com.lanan.springboot.model.Tag;
import com.lanan.springboot.model.User;
import com.lanan.springboot.plugin.RedisService;
import com.lanan.springboot.service.*;
import com.lanan.springboot.util.bcrypt.BCryptPasswordEncoder;
import com.lanan.springboot.util.*;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @desc IndexApiController
 * @author lanan
 * @date 2022-04-09 21:49:43
 **/
@RestController
@RequestMapping("/api")
public class IndexApiController extends BaseApiController {

    @Value("${email.time}")
    private String time;

    @Resource
    private IUserService userService;
    @Resource
    private ISystemConfigService systemConfigService;
    @Resource
    private CookieUtil cookieUtil;
    @Resource
    private ITopicService topicService;
    @Resource
    private ITagService tagService;
    @Resource
    private FileUtil fileUtil;
    @Resource
    private ICodeService codeService;
    @Resource
    private RedisService redisService;

    /**
     * @desc 首页接口
     * @author lanan
     * @date 2022-04-09 21:44:26
     * @param pageNo
     * @param tab
     * @return com.lanan.springboot.util.Result
     **/
    @GetMapping({"/", "/index"})
    public Result index(@RequestParam(defaultValue = "1") Integer pageNo, @RequestParam(defaultValue = "all") String
            tab) {
        MyPage<Map<String, Object>> page = topicService.selectAll(pageNo, tab);
        for (Map<String, Object> map : page.getRecords()) {
            Object content = map.get("content");
            map.put("content", StringUtils.isEmpty(content) ? null : SensitiveWordUtil.replaceSensitiveWord(content
                    .toString(), "*", SensitiveWordUtil.MinMatchType));
        }
        return success(page);
    }

    /**
     * @desc 根据标签名返回标签下话题
     * @author lanan
     * @date 2022-04-09 21:44:19
     * @param pageNo
     * @param name
     * @return com.lanan.springboot.util.Result
     **/
    @GetMapping("/tag/{name}")
    public Result topicsByTagName(@RequestParam(defaultValue = "1") Integer pageNo, @PathVariable String name) {
        Tag tag = tagService.selectByName(name);
        if (tag == null) {
            return error("标签不存在");
        } else {
            MyPage<Map<String, Object>> iPage = tagService.selectTopicByTagId(tag.getId(), pageNo);
            Map<String, Object> result = new HashMap<>();
            result.put("tag", tag);
            result.put("page", iPage);
            return success(result);
        }
    }

    /**
     * @desc 处理登录的接口
     * @author lanan
     * @date 2022-04-09 21:44:07
     * @param body
     * @param session
     * @return com.lanan.springboot.util.Result
     **/
    @PostMapping("/login")
    public Result login(@RequestBody Map<String, String> body, HttpSession session) {
        String username = body.get("username");
        String password = body.get("password");
        String captcha = body.get("captcha");
        String _captcha = (String) session.getAttribute("_captcha");
        ApiAssert.notTrue(_captcha == null || StringUtils.isEmpty(captcha), "验证码不正确,请刷新网页");
        ApiAssert.notTrue(!_captcha.equalsIgnoreCase(captcha), "验证码不正确");
        ApiAssert.notEmpty(username, "请输入用户名");
        ApiAssert.notEmpty(password, "请输入密码");
        User user = userService.selectByUsername(username);
        ApiAssert.notNull(user, "用户不存在");
        ApiAssert.isTrue(new BCryptPasswordEncoder().matches(password, user.getPassword()), "用户名或密码不正确");
        return this.doUserStorage(session, user);
    }

    /**
     * @desc 处理注册的接口
     * @author lanan
     * @date 2022-04-09 21:43:56
     * @param body
     * @param session
     * @return com.lanan.springboot.util.Result
     **/
    @PostMapping("/register")
    public Result register(@RequestBody Map<String, String> body, HttpSession session) {
        String username = body.get("username");
        String password = body.get("password");
        String email = body.get("email");
        String captcha = body.get("captcha");
        String code = (String) session.getAttribute("_captcha");
        ApiAssert.notTrue(code == null || StringUtils.isEmpty(captcha), "请输入验证码");
        ApiAssert.notTrue(!code.equalsIgnoreCase(captcha), "验证码不正确");
        ApiAssert.notEmpty(username, "请输入用户名");
        ApiAssert.notEmpty(password, "请输入密码");
        ApiAssert.notEmpty(email, "请输入邮箱");
        ApiAssert.isTrue(StringUtil.check(username, StringUtil.USERNAMEREGEX), "用户名只能为a-z,A-Z,0-9组合且2-16位");
        ApiAssert.isTrue(StringUtil.check(email, StringUtil.EMAILREGEX), "请输入正确的邮箱地址");
        User user = userService.selectByUsername(username);
        ApiAssert.isNull(user, "用户名已存在");
        User emailUser = userService.selectByEmail(email);
        ApiAssert.isNull(emailUser, "这个邮箱已经被注册过了，请更换一个邮箱");
        user = userService.addUser(username, password, null, email, null, null, true);
        return this.doUserStorage(session, user);
    }


    /**
     * @desc 发送手机验证码
     * @author lanan
     * @date 2022-04-09 21:43:37
     * @param captcha
     * @param mobile
     * @param session
     * @return com.lanan.springboot.util.Result
     **/
    @GetMapping("/sms_code")
    public Result sms_code(String captcha, String mobile, HttpSession session) {
        String _captcha = (String) session.getAttribute("_captcha");
        ApiAssert.notTrue(_captcha == null || StringUtils.isEmpty(captcha), "请输入验证码");
        ApiAssert.notTrue(!_captcha.equalsIgnoreCase(captcha), "验证码不正确");
        ApiAssert.notEmpty(mobile, "请输入手机号");
        ApiAssert.isTrue(StringUtil.check(mobile, StringUtil.MOBILEREGEX), "请输入正确的手机号");
        boolean b = codeService.sendSms(mobile);
        if (!b) {
            return error("短信发送失败或者站长没有配置短信服务");
        } else {
            return success();
        }
    }

    /**
     * @desc 手机号+验证码登录
     * @author lanan
     * @date 2022-04-09 21:43:30
     * @param body
     * @param session
     * @return com.lanan.springboot.util.Result
     **/
    @PostMapping("/mobile_login")
    public Result mobile_login(@RequestBody Map<String, String> body, HttpSession session) {
        String mobile = body.get("mobile");
        String code = body.get("code");
        String captcha = body.get("captcha");
        String _captcha = (String) session.getAttribute("_captcha");
        ApiAssert.notTrue(_captcha == null || StringUtils.isEmpty(captcha), "请输入验证码");
        ApiAssert.notTrue(!_captcha.equalsIgnoreCase(captcha), "验证码不正确");
        ApiAssert.notEmpty(mobile, "请输入手机号");
        ApiAssert.isTrue(StringUtil.check(mobile, StringUtil.MOBILEREGEX), "请输入正确的手机号");
        ApiAssert.notEmpty(code, "请输入手机验证码");
        Code validateCode = codeService.validateCode(null, null, mobile, code);
        ApiAssert.notTrue(validateCode == null, "手机验证码错误");
        User user = userService.addUserWithMobile(mobile);
        return doUserStorage(session, user);
    }


    @PostMapping("email_login")
    public Result email_login(@RequestBody Map<String, String> body, HttpSession session) {
        String email = body.get("email");
        String password = body.get("password");
        ApiAssert.notEmpty(email, "请输入邮箱");
        ApiAssert.isTrue(StringUtil.check(email, StringUtil.EMAILREGEX), "请输入正确的邮箱");
        ApiAssert.notEmpty(password, "请输入密码");
        ApiAssert.isTrue(StringUtil.check(password, StringUtil.PASSWORDREGEX), "请输入正确的密码");
        User user = userService.selectByEmail(email);
        ApiAssert.notNull(user, "用户不存在");
        ApiAssert.isTrue(new BCryptPasswordEncoder().matches(password, user.getPassword()), "密码不正确");
        return this.doUserStorage(session, user);
    }

     /**
      * @desc 发送邮件来重置密码
      * @author lanan
      * @date 2022-04-09 21:22:38
      * @param body
      * @param session
      * @return com.lanan.springboot.util.Result
      **/
      @PostMapping("/forget_password")
      public Result forget_password(@RequestBody Map<String, String> body, HttpSession session) {
          String e = body.get("email");
          String c = body.get("captcha");
          String p = body.get("password");
          String email = StringUtils.isEmpty(e) ? null : e;
          String code = StringUtils.isEmpty(c) ? null : c;
          String password = StringUtils.isEmpty(p) ? null : p;
          ApiAssert.notTrue(code == null, "请输入验证码");
          ApiAssert.notTrue(email == null, "请输入邮箱");
          ApiAssert.notTrue(password == null, "请输入密码");
          ApiAssert.isTrue(StringUtil.check(email, StringUtil.EMAILREGEX), "请输入正确的邮箱地址");
          ApiAssert.isTrue(StringUtil.check(password, StringUtil.PASSWORDREGEX), "密码格式错误");
          // 验证重置密码是否与原密码一致
          User user = userService.selectByEmail(email);
          ApiAssert.notTrue(ObjectUtils.isEmpty(user), "邮箱未注册，请检查邮箱");
          String encode = new BCryptPasswordEncoder().encode(password);
          if (user.getPassword().equals(encode)) {
              throw new ApiException("重置密码不能与原密码一致!");
          }
          Map<String, Object> map = (Map<String, Object>) session.getAttribute("email");
          Long emailTime = (Long) map.get("emailTime");
          String emailCode = (String) map.get("emailCode");
          ApiAssert.notTrue(!code.equalsIgnoreCase(emailCode), "邮箱验证码不正确");
          if (ObjectUtils.isEmpty(map)) {
              throw new ApiException("验证码失效，请重新发送邮箱验证码！");
          }else {
              if (System.currentTimeMillis() - emailTime > Long.parseLong(time)) {
                  throw new ApiException("验证码过期");
              } else {
                  // 根据邮箱修改密码
                  if (userService.updateUserPwdByEmail(email, encode) != 1) {
                      // 修改失败，返回错误
                      return error("修改密码失败，请重新填写");
                  } else {
                      return success();
                  }
              }
          }
      }

    /**
     * @desc 登录成功后，处理的逻辑一样，这里提取出来封装一个方法处理
     * @author lanan
     * @date 2022-04-09 21:42:54
     * @param session
     * @param user
     * @return com.lanan.springboot.util.Result
     **/
    private Result doUserStorage(HttpSession session, User user) {
        // 将用户信息写session
        if (session != null) {
            session.setAttribute("_user", user);
            session.removeAttribute("_captcha");
        }
        // 将用户token写入redis  默认一个星期
//        String key = user.getUsername() + "Token";
//        if (!user.getToken().equals(redisService.getString(key) + "")) {
//            redisService.setString(key, user.getToken(), 7 * 24 * 60 * 60);
//        }
        // 将用户token写cookie
        cookieUtil.setCookie(systemConfigService.selectAllConfig().get("cookie_name") + "", user.getToken());
        Map<String, Object> map = new HashMap<>(2);
        map.put("user", user);
        map.put("token", user.getToken());
        return success(map);
    }

    /**
     * @desc 标签接口
     * @author lanan
     * @date 2022-04-09 21:43:05
     * @param pageNo
     * @return com.lanan.springboot.util.Result
     **/
    @GetMapping("/tags")
    public Result tags(@RequestParam(defaultValue = "1") Integer pageNo) {
        return success(tagService.selectAll(pageNo, null, null));
    }

    /**
     * @desc 上传图片
     * @author lanan
     * @date 2022-04-09 21:43:12
     * @param files
     * @param type
     * @param session
     * @return com.lanan.springboot.util.Result
     **/
    @PostMapping("/upload")
    @ResponseBody
    public Result upload(@RequestParam("file") MultipartFile[] files, String type, HttpSession session) {
        User user = getApiUser();
        ApiAssert.isTrue(user.getActive(), "你的帐号还没有激活，请去个人设置页面激活帐号");
        ApiAssert.notEmpty(type, "上传文件类型不能为空");
        Map<String, Object> resultMap = new HashMap<>(16);
        List<String> urls = new ArrayList<>();
        List<String> errors = new ArrayList<>();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd/");
        String path = formatter.format(new Date());
        for (int i = 0; i < files.length; i++) {
            String url;
            MultipartFile file = files[i];
            String suffix = "." + Objects.requireNonNull(file.getContentType()).split("/")[1];
            if (!Arrays.asList(".jpg", ".png", ".gif", ".jpeg", ".mp4").contains(suffix.toLowerCase())) {
                errors.add("第[" + (i + 1) + "]个文件异常: " + "文件格式不正确");
                continue;
            }
            long size = file.getSize();
            // 根据不同上传类型，对文件大小做校验
            if ("video".equalsIgnoreCase(type)) {
                long uploadVideoSizeLimit = Long.parseLong(systemConfigService.selectAllConfig().get("upload_video_size_limit").toString());
                if (size > uploadVideoSizeLimit * 1024 * 1024) {
                    errors.add("第[" + (i + 1) + "]个文件异常: " + "文件太大了，请上传文件大小在 " + uploadVideoSizeLimit + "MB 以内");
                    continue;
                }
            } else {
                long uploadImageSizeLimit = Long.parseLong(systemConfigService.selectAllConfig().get("upload_image_size_limit").toString());
                if (size > uploadImageSizeLimit * 1024 * 1024) {
                    errors.add("第[" + (i + 1) + "]个文件异常: " + "文件太大了，请上传文件大小在 " + uploadImageSizeLimit + "MB 以内");
                    continue;
                }
            }
            // 上传头像
            if ("avatar".equalsIgnoreCase(type)) {
                // 拿到上传后访问的url
                url = fileUtil.upload(file, "avatar", path + "avatar/" + user.getUsername() + "/");
                if (url != null) {
                    // 查询当前用户的最新信息
                    User user1 = userService.selectById(user.getId());
                    user1.setAvatar(url);
                    // 保存用户新的头像
                    userService.update(user1);
                    // 将最新的用户信息更新在session里
                    if (session != null) {
                        session.setAttribute("_user", user1);
                    }
                }
            }
            // 发帖上传图片
            else if ("topic".equalsIgnoreCase(type)) {
                url = fileUtil.upload(file, null, path + "topic/" + user.getUsername() + "/");
            }
            // 视频上传
            else if ("video".equalsIgnoreCase(type)) {
                url = fileUtil.upload(file, null, path + "video/" + user.getUsername() + "/");
            } else {
                errors.add("第[" + (i + 1) + "]个文件异常: " + "上传图片类型不在处理范围内");
                continue;
            }
            if (url == null) {
                errors.add("第[" + (i + 1) + "]个文件异常: " + "上传的文件不存在或者上传过程发生了错误");
                continue;
            }
            urls.add(url);
        }
        resultMap.put("urls", urls);
        resultMap.put("errors", errors);
        return success(resultMap);
    }

}
